package com.school.sports.service.Impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.school.sports.entity.Schedule;
import com.school.sports.mapper.ScheduleMapper;
import com.school.sports.service.ScheduleService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.time.LocalTime;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * 赛程服务实现类
 */
@Slf4j
@Service
public class ScheduleServiceImpl extends ServiceImpl<ScheduleMapper, Schedule> implements ScheduleService {

    @Override
    public IPage<Schedule> page(Page<Schedule> page, LambdaQueryWrapper<Schedule> queryWrapper) {
        return baseMapper.selectPage(page, queryWrapper);
    }

    @Override
    public Schedule getScheduleWithDetails(Long id) {
        return baseMapper.selectScheduleWithDetails(id);
    }

    @Override
    @Transactional
    public boolean createSchedule(Schedule schedule) {
        try {
            // 检查时间是否合理
            if (schedule.getStartTime().isAfter(schedule.getEndTime())) {
                log.warn("开始时间不能晚于结束时间");
                return false;
            }

            // 检查场地时间冲突
            if (checkVenueTimeConflict(schedule.getVenueId(), schedule.getStartTime(), schedule.getEndTime(), null)) {
                log.warn("场地时间冲突，场地ID：{}", schedule.getVenueId());
                return false;
            }

            // 检查裁判时间冲突（如果分配了裁判）
            if (schedule.getRefereeId() != null) {
                if (checkRefereeTimeConflict(schedule.getRefereeId(), schedule.getStartTime(), schedule.getEndTime(), null)) {
                    log.warn("裁判时间冲突，裁判ID：{}", schedule.getRefereeId());
                    return false;
                }
            }

            // 设置默认状态和创建时间
            if (schedule.getStatus() == null || schedule.getStatus().isEmpty()) {
                schedule.setStatus("未开始");
            }
            if (schedule.getRound() == null) {
                schedule.setRound(1);
            }
            schedule.setCreatedAt(LocalDateTime.now());

            return save(schedule);
        } catch (Exception e) {
            log.error("创建赛程失败：{}", e.getMessage(), e);
            return false;
        }
    }

    @Override
    @Transactional
    public boolean updateSchedule(Schedule schedule) {
        try {
            Schedule existingSchedule = getById(schedule.getId());
            if (existingSchedule == null) {
                log.warn("赛程不存在，ID：{}", schedule.getId());
                return false;
            }

            // 检查是否可以修改
            if (existingSchedule.isCompleted() || existingSchedule.isCancelled()) {
                log.warn("已结束或已取消的赛程不能修改，ID：{}", schedule.getId());
                return false;
            }

            // 检查时间是否合理
            if (schedule.getStartTime().isAfter(schedule.getEndTime())) {
                log.warn("开始时间不能晚于结束时间");
                return false;
            }

            // 检查场地时间冲突
            if (checkVenueTimeConflict(schedule.getVenueId(), schedule.getStartTime(), schedule.getEndTime(), schedule.getId())) {
                log.warn("场地时间冲突，场地ID：{}", schedule.getVenueId());
                return false;
            }

            // 检查裁判时间冲突（如果分配了裁判）
            if (schedule.getRefereeId() != null) {
                if (checkRefereeTimeConflict(schedule.getRefereeId(), schedule.getStartTime(), schedule.getEndTime(), schedule.getId())) {
                    log.warn("裁判时间冲突，裁判ID：{}", schedule.getRefereeId());
                    return false;
                }
            }

            // 保持原有的创建时间和状态
            schedule.setCreatedAt(existingSchedule.getCreatedAt());

            return updateById(schedule);
        } catch (Exception e) {
            log.error("更新赛程失败：{}", e.getMessage(), e);
            return false;
        }
    }

    @Override
    @Transactional
    public boolean deleteSchedule(Long id) {
        try {
            Schedule schedule = getById(id);
            if (schedule == null) {
                log.warn("赛程不存在，ID：{}", id);
                return false;
            }

            // 检查是否可以删除
            if (schedule.isInProgress()) {
                log.warn("进行中的赛程不能删除，ID：{}", id);
                return false;
            }

            return removeById(id);
        } catch (Exception e) {
            log.error("删除赛程失败：{}", e.getMessage(), e);
            return false;
        }
    }

    @Override
    @Transactional
    public boolean updateScheduleStatus(Long id, String status) {
        try {
            Schedule schedule = getById(id);
            if (schedule == null) {
                return false;
            }

            // 检查状态流转是否合法
            if (!isValidStatusTransition(schedule.getStatus(), status)) {
                log.warn("非法的状态流转：{} -> {}", schedule.getStatus(), status);
                return false;
            }

            schedule.setStatus(status);
            return updateById(schedule);
        } catch (Exception e) {
            log.error("更新赛程状态失败：{}", e.getMessage(), e);
            return false;
        }
    }

    @Override
    @Transactional
    public boolean startSchedule(Long id) {
        return updateScheduleStatus(id, "进行中");
    }

    @Override
    @Transactional
    public boolean endSchedule(Long id) {
        return updateScheduleStatus(id, "已结束");
    }

    @Override
    @Transactional
    public boolean postponeSchedule(Long id, LocalDateTime newStartTime, LocalDateTime newEndTime) {
        try {
            Schedule schedule = getById(id);
            if (schedule == null) {
                return false;
            }

            if (!schedule.canPostpone()) {
                log.warn("当前状态不能延期，状态：{}", schedule.getStatus());
                return false;
            }

            // 检查新时间是否合理
            if (newStartTime.isAfter(newEndTime)) {
                log.warn("新的开始时间不能晚于结束时间");
                return false;
            }

            // 检查场地时间冲突
            if (checkVenueTimeConflict(schedule.getVenueId(), newStartTime, newEndTime, id)) {
                log.warn("新的时间存在场地冲突");
                return false;
            }

            // 检查裁判时间冲突
            if (schedule.getRefereeId() != null) {
                if (checkRefereeTimeConflict(schedule.getRefereeId(), newStartTime, newEndTime, id)) {
                    log.warn("新的时间存在裁判冲突");
                    return false;
                }
            }

            schedule.setStartTime(newStartTime);
            schedule.setEndTime(newEndTime);
            schedule.setStatus("延期");

            return updateById(schedule);
        } catch (Exception e) {
            log.error("延期赛程失败：{}", e.getMessage(), e);
            return false;
        }
    }

    @Override
    @Transactional
    public boolean cancelSchedule(Long id) {
        return updateScheduleStatus(id, "取消");
    }

    @Override
    public boolean checkVenueTimeConflict(Integer venueId, LocalDateTime startTime, LocalDateTime endTime, Long excludeId) {
        LambdaQueryWrapper<Schedule> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Schedule::getVenueId, venueId)
                .ne(Schedule::getStatus, "取消")
                .and(wrapper -> wrapper
                        .lt(Schedule::getStartTime, endTime)
                        .gt(Schedule::getEndTime, startTime)
                );

        if (excludeId != null) {
            queryWrapper.ne(Schedule::getId, excludeId);
        }

        return count(queryWrapper) > 0;
    }

    @Override
    public boolean checkRefereeTimeConflict(Long refereeId, LocalDateTime startTime, LocalDateTime endTime, Long excludeId) {
        if (refereeId == null) {
            return false;
        }

        LambdaQueryWrapper<Schedule> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Schedule::getRefereeId, refereeId)
                .ne(Schedule::getStatus, "取消")
                .and(wrapper -> wrapper
                        .lt(Schedule::getStartTime, endTime)
                        .gt(Schedule::getEndTime, startTime)
                );

        if (excludeId != null) {
            queryWrapper.ne(Schedule::getId, excludeId);
        }

        return count(queryWrapper) > 0;
    }

    @Override
    public List<Schedule> getSchedulesByProjectId(Long projectId) {
        LambdaQueryWrapper<Schedule> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Schedule::getProjectId, projectId)
                .orderByAsc(Schedule::getStartTime);
        return list(queryWrapper);
    }

    @Override
    public List<Schedule> getSchedulesByVenueId(Integer venueId) {
        LambdaQueryWrapper<Schedule> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Schedule::getVenueId, venueId)
                .orderByAsc(Schedule::getStartTime);
        return list(queryWrapper);
    }

    @Override
    public List<Schedule> getSchedulesByRefereeId(Long refereeId) {
        if (refereeId == null) {
            return Collections.emptyList();
        }

        LambdaQueryWrapper<Schedule> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Schedule::getRefereeId, refereeId)
                .orderByAsc(Schedule::getStartTime);
        return list(queryWrapper);
    }

    @Override
    public List<Schedule> getSchedulesByStatus(String status) {
        LambdaQueryWrapper<Schedule> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(Schedule::getStatus, status)
                .orderByAsc(Schedule::getStartTime);
        return list(queryWrapper);
    }

    @Override
    public List<Schedule> getSchedulesByDateRange(LocalDateTime startDate, LocalDateTime endDate) {
        LambdaQueryWrapper<Schedule> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.ge(Schedule::getStartTime, startDate)
                .le(Schedule::getStartTime, endDate)
                .orderByAsc(Schedule::getStartTime);
        return list(queryWrapper);
    }

    @Override
    public List<Schedule> getTodaySchedules() {
        LocalDateTime todayStart = LocalDateTime.now().with(LocalTime.MIN);
        LocalDateTime todayEnd = LocalDateTime.now().with(LocalTime.MAX);
        return getSchedulesByDateRange(todayStart, todayEnd);
    }

    @Override
    public List<Schedule> getWeekSchedules() {
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime weekStart = now.with(java.time.temporal.TemporalAdjusters.previousOrSame(java.time.DayOfWeek.MONDAY)).with(LocalTime.MIN);
        LocalDateTime weekEnd = now.with(java.time.temporal.TemporalAdjusters.nextOrSame(java.time.DayOfWeek.SUNDAY)).with(LocalTime.MAX);
        return getSchedulesByDateRange(weekStart, weekEnd);
    }

    @Override
    public List<Schedule> getUpcomingSchedules() {
        LocalDateTime now = LocalDateTime.now();
        LocalDateTime tomorrow = now.plusDays(1);

        LambdaQueryWrapper<Schedule> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.gt(Schedule::getStartTime, now)
                .le(Schedule::getStartTime, tomorrow)
                .ne(Schedule::getStatus, "取消")
                .orderByAsc(Schedule::getStartTime);
        return list(queryWrapper);
    }

    @Override
    public Map<String, Long> getScheduleStatusStatistics() {
        Map<String, Long> statistics = new HashMap<>();
        List<String> statuses = getAllScheduleStatuses();

        for (String status : statuses) {
            LambdaQueryWrapper<Schedule> queryWrapper = new LambdaQueryWrapper<>();
            queryWrapper.eq(Schedule::getStatus, status);
            long count = count(queryWrapper);
            statistics.put(status, count);
        }

        return statistics;
    }

    @Override
    public List<String> getAllScheduleStatuses() {
        return Arrays.asList("未开始", "进行中", "已结束", "延期", "取消");
    }

    @Override
    @Transactional
    public boolean assignReferee(Long scheduleId, Long refereeId) {
        try {
            Schedule schedule = getById(scheduleId);
            if (schedule == null) {
                return false;
            }

            // 检查裁判时间冲突
            if (checkRefereeTimeConflict(refereeId, schedule.getStartTime(), schedule.getEndTime(), scheduleId)) {
                log.warn("裁判时间冲突，无法分配");
                return false;
            }

            schedule.setRefereeId(refereeId);
            return updateById(schedule);
        } catch (Exception e) {
            log.error("分配裁判失败：{}", e.getMessage(), e);
            return false;
        }
    }

    @Override
    @Transactional
    public boolean changeReferee(Long scheduleId, Long newRefereeId) {
        try {
            Schedule schedule = getById(scheduleId);
            if (schedule == null) {
                return false;
            }

            // 检查新裁判时间冲突
            if (checkRefereeTimeConflict(newRefereeId, schedule.getStartTime(), schedule.getEndTime(), scheduleId)) {
                log.warn("新裁判时间冲突，无法更换");
                return false;
            }

            schedule.setRefereeId(newRefereeId);
            return updateById(schedule);
        } catch (Exception e) {
            log.error("更换裁判失败：{}", e.getMessage(), e);
            return false;
        }
    }

    @Override
    public boolean isVenueAvailable(Integer venueId, LocalDateTime startTime, LocalDateTime endTime) {
        return !checkVenueTimeConflict(venueId, startTime, endTime, null);
    }

    @Override
    public boolean isRefereeAvailable(Long refereeId, LocalDateTime startTime, LocalDateTime endTime) {
        if (refereeId == null) {
            return true;
        }
        return !checkRefereeTimeConflict(refereeId, startTime, endTime, null);
    }

    /**
     * 检查状态流转是否合法
     */
    private boolean isValidStatusTransition(String currentStatus, String newStatus) {
        if (currentStatus.equals(newStatus)) {
            return true;
        }

        // 定义合法的状态流转
        Map<String, List<String>> validTransitions = new HashMap<>();
        validTransitions.put("未开始", Arrays.asList("进行中", "延期", "取消"));
        validTransitions.put("进行中", Arrays.asList("已结束", "延期", "取消"));
        validTransitions.put("延期", Arrays.asList("未开始", "进行中", "取消"));
        validTransitions.put("已结束", Collections.emptyList());
        validTransitions.put("取消", Collections.emptyList());

        return validTransitions.getOrDefault(currentStatus, Collections.emptyList()).contains(newStatus);
    }
}